package edu.ccut.saturn.studio.deploy;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import edu.ccut.saturn.studio.Activator;
import edu.ccut.saturn.studio.core.exception.XMLException;
import edu.ccut.saturn.studio.core.http.SaturnHttpRequester;
import edu.ccut.saturn.studio.core.util.eclipse.Messages;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnBundleUtil;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnDialogSettings;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnDialogUtil;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnProjectUtil;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnSWTUtils;
import edu.ccut.saturn.studio.core.util.freemaker.FreemarkerUtils;
import edu.ccut.saturn.studio.core.util.xml.SaturnW3CUtil;
import edu.ccut.saturn.studio.naviagtor.wizard.project.SaturnProjectNature;
import edu.ccut.saturn.studio.server.dialog.NewSaturnServerDialog;
import edu.ccut.saturn.studio.server.model.SaturnServer;
import edu.ccut.saturn.studio.server.model.SaturnServerModel;

public class DeployDialog extends TitleAreaDialog {

	private Text path1;
	public static final String STORE_SERVER_NAME_KEY = "server.name"; //$NON-NLS-1$
	public static final String STORE_SECTION_NAME = "edu.ccut.saturn.studio.deploy"; //$NON-NLS-1$

	private static final String DEPLOY_FTL = "template/deploy.ftl"; //$NON-NLS-1$
	private static final String BUILD_XML = "build.xml"; //$NON-NLS-1$
	private Combo combo;
	private Table table;
	private CheckboxTableViewer projectTableViewer;
	private String selectprojectName = ""; //$NON-NLS-1$
	private Map<String, SaturnServer> saturnServers = null;
	private String comboValue = ""; //$NON-NLS-1$

	private List<String> results = new ArrayList<String>();

	public DeployDialog(Shell parentShell, String projectName) {
		super(parentShell);
		this.selectprojectName = projectName;
		saturnServers = SaturnServerModel.getSaturnServers();
	}

	protected Point getInitialSize() {
		return new Point(721, 343);
	}

	protected int getShellStyle() {
		return SWT.CLOSE | SWT.RESIZE;
	}

	protected Control createDialogArea(Composite parent) {
		Composite area = (Composite) super.createDialogArea(parent);
		Composite container = new Composite(area, SWT.NONE);
		final GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 3;
		container.setLayout(gridLayout);
		final GridData gd_container = new GridData(SWT.FILL, SWT.FILL, false,
				false);
		gd_container.heightHint = 191;
		container.setLayoutData(gd_container);

		final Label saturnServerLabel = new Label(container, SWT.NONE);
		final GridData gd_saturnServerLabel = new GridData();
		saturnServerLabel.setLayoutData(gd_saturnServerLabel);
		saturnServerLabel.setText("SATURN SERVER:"); //$NON-NLS-1$

		combo = new Combo(container, SWT.READ_ONLY);
		combo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				comboValue = combo.getText().trim();
				iniDepolyLabel(getDepolyPath(comboValue));
			}
		});
		combo.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				comboValue = combo.getText().trim();
				iniDepolyLabel(getDepolyPath(comboValue));
			}
		});
		combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

		combo.setItems(saturnServers.keySet().toArray(new String[0]));
		combo.select(0);

		final Button button_1 = new Button(container, SWT.NONE);
		button_1.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				NewSaturnServerDialog dialog = new NewSaturnServerDialog(Display
						.getDefault().getShells()[0], saturnServers);
				dialog.open();
				combo.setItems(saturnServers.keySet().toArray(new String[0]));
				SaturnServerModel.saveSaturnServers(saturnServers);
				String serverName = dialog.getSaturnServerName();
				if (serverName == null) {
					combo.select(0);
				} else {
					combo.select(combo.indexOf(serverName));
				}
			}
		});
		button_1.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.New")); //$NON-NLS-1$

		final Label label = new Label(container, SWT.NONE);
		final GridData gd_label = new GridData();
		gd_label.verticalIndent = 10;
		label.setLayoutData(gd_label);
		label.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.DeployProject")); //$NON-NLS-1$

		final TableViewer tableViewer = new TableViewer(container,
				SWT.FULL_SELECTION | SWT.BORDER | SWT.CHECK);
		table = tableViewer.getTable();

		projectTableViewer = new CheckboxTableViewer(tableViewer.getTable());
		table.setLinesVisible(true);
		table.setHeaderVisible(true);

		final GridData gd_table = new GridData(SWT.FILL, SWT.FILL, true, true,
				1, 2);
		gd_table.verticalIndent = 5;
		table.setLayoutData(gd_table);

		final TableColumn newColumnTableColumn = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn.setWidth(222);
		newColumnTableColumn
				.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
						.getString("DeployDialog.ProjectName")); //$NON-NLS-1$

		final TableColumn newColumnTableColumn_1 = new TableColumn(table,
				SWT.NONE);
		newColumnTableColumn_1.setWidth(250);
		newColumnTableColumn_1
				.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
						.getString("DeployDialog.DeployPackage")); //$NON-NLS-1$

		tableViewer
				.setContentProvider(new SaturnSWTUtils.SaturnTableViewerDefaultContentProvider());
		tableViewer
				.setLabelProvider(new SaturnSWTUtils.SaturnTableViewerDefaultLabelProvider() {

					@Override
					public String getColumnText(Object obj, int index) {
						return ((IProject) obj).getName();
					}
				});

		List<IProject> projects = findProjectsMap();
		Collections.sort(projects, new Comparator<IProject>() {
			public int compare(IProject o1, IProject o2) {
				return o1.getName().compareTo(o2.getName());
			}
		});

		tableViewer.setInput(projects);
		tableViewer.setColumnProperties(new String[] { "project name" }); //$NON-NLS-1$

		final Button button = new Button(container, SWT.NONE);
		final GridData gd_button = new GridData(SWT.FILL, SWT.CENTER, false,
				false);
		gd_button.verticalIndent = 5;
		button.setLayoutData(gd_button);
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				TableItem items[] = tableViewer.getTable().getItems();
				for (int i = 0; i < items.length; i++) {
					items[i].setChecked(true);
				}
			}
		});
		button.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.selectAll")); //$NON-NLS-1$
		new Label(container, SWT.NONE);

		final Button button_2 = new Button(container, SWT.NONE);
		button_2.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				TableItem items[] = tableViewer.getTable().getItems();
				for (int i = 0; i < items.length; i++) {
					if (items[i].getChecked()) {
						items[i].setChecked(false);
					} else {
						items[i].setChecked(true);
					}
				}
			}
		});
		final GridData gd_button_2 = new GridData();
		gd_button_2.verticalIndent = 10;
		button_2.setLayoutData(gd_button_2);
		button_2.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.selectBack")); //$NON-NLS-1$

		final Label label_2 = new Label(container, SWT.NONE);
		label_2.setText(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.DeployPath")); //$NON-NLS-1$

		path1 = new Text(container, SWT.READ_ONLY | SWT.BORDER);
		final GridData gd_path1 = new GridData(SWT.FILL, SWT.CENTER, true,
				false);
		path1.setLayoutData(gd_path1);
		comboValue = combo.getText();
		String depolyPath = getDepolyPath(comboValue);

		iniDepolyLabel(depolyPath);

		if (selectprojectName != null) {
			for (IProject project : projects) {
				if (project.getName().equals(selectprojectName)) {
					projectTableViewer
							.setCheckedElements(new Object[] { project });
				}
			}
		}
		setMessage(edu.ccut.saturn.studio.core.util.eclipse.Messages
				.getString("DeployDialog.DeployMessage")); //$NON-NLS-1$
		restoreWidgetValues();
		return area;
	}

	private void iniDepolyLabel(String depolyPath) {
		if (this.path1 != null) {
			path1.setText(depolyPath);
		}
	}

	private List<IProject> getSelection() {

		List<IProject> selecteds = new ArrayList<IProject>();

		if (projectTableViewer != null) {
			Object[] checkeds = projectTableViewer.getCheckedElements();
			for (Object checked : checkeds) {
				selecteds.add((IProject) checked);
			}
			return selecteds;
		}

		return null;
	}

	private List<IProject> findProjectsMap() {
		List<IProject> availdProject = new ArrayList<IProject>();

		IProject projects[] = SaturnProjectUtil.getAllProjects();

		for (IProject project : projects) {
			try {
				if (project.isOpen()
						&& project.hasNature(SaturnProjectNature.PROJECT_NATURE)) {
					availdProject.add(project);
				}
			} catch (CoreException e) {
				e.printStackTrace();
			}
		}

		return availdProject;
	}

	protected void buttonPressed(int buttonId) {
		if (buttonId == IDialogConstants.OK_ID) {
			if (this.comboValue.equals("") || this.comboValue == null) { //$NON-NLS-1$
				MessageDialog
						.openInformation(
								null,
								edu.ccut.saturn.studio.core.util.eclipse.Messages
										.getString("DeployDialog.Error"), edu.ccut.saturn.studio.core.util.eclipse.Messages.getString("DeployDialog.NewConfiguration")); //$NON-NLS-1$ //$NON-NLS-2$
				return;
			}

			final List<IProject> projects = getSelection();

			try {
				new ProgressMonitorDialog(getShell()).run(true, false,
						new IRunnableWithProgress() {
							public void run(IProgressMonitor monitor)
									throws InvocationTargetException {
								if (projects == null || projects.isEmpty()) {
									MessageBox messageBox = new MessageBox(
											getShell(), SWT.ICON_INFORMATION
													| SWT.YES);
									messageBox.setText("Information"); //$NON-NLS-1$
									messageBox
											.setMessage(edu.ccut.saturn.studio.core.util.eclipse.Messages
													.getString("DeployDialog.SelectDeployProject")); //$NON-NLS-1$
									messageBox.open();

									return;
								}

								monitor
										.beginTask(
												edu.ccut.saturn.studio.core.util.eclipse.Messages
														.getString("DeployDialog.DeployProgress"), 100); //$NON-NLS-1$

								for (IProject project : projects) {
									antDeloy(project, getDepolyPath(comboValue));
								}
							}
						});
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}

		SaturnServerModel.saveSaturnServers(saturnServers);
		saveWidgetValues();
		
//		ILogger  logger = SaturnLoggerManager.getInstance().getSaturnLogger(SaturnLoggerManager.DEFAULT_LEVEL);
		if (!results.isEmpty()) {
			StringBuffer message = new StringBuffer();
			for (String result : results) {
				message.append(result).append('\n');
//				logger.info(result);
			}
			
			SaturnDialogUtil.openInformation(super.getShell(), message
					.toString());
		}

		super.buttonPressed(buttonId);
	}

	private void antDeloy(IProject project, String location) {
		String projectName = project.getName();

		String buildxmlpath = project.getLocation().toString() + File.separator
				+ BUILD_XML;

		String version = Messages.getString("DeployDialog.0"); //$NON-NLS-1$

		try {
			version = SaturnBundleUtil.getBundleAttribute(project,
					Messages.getString("DeployDialog.1")); //$NON-NLS-1$
		} catch (Exception e) {
			// 不处理异常，默认为 1.0.0
		}

		Map<String, String> values = new HashMap<String, String>();
		values.put("name", projectName); //$NON-NLS-1$
		values.put("location", location); //$NON-NLS-1$
		values.put("version", version); //$NON-NLS-1$

		FreemarkerUtils.writeTemplateToFile(DEPLOY_FTL, values, buildxmlpath);
		SaturnProjectUtil.refreshProject(projectName);

		antBuild(project);
		doGetUpdateBundles(project);
	}

	/**
	 * 执行ant文件中默认的任务
	 * 
	 * @param project
	 */
	private void antBuild(IProject project) {
		IPath location = project.getLocation();
		IFile ifile = project.getFile(BUILD_XML);

		File antFile = ifile.getLocation().toFile();
		Project antProject = new Project();
		antProject.setBasedir(location.toFile().getAbsolutePath());

		DefaultLogger consoleLogger = new DefaultLogger();
		consoleLogger.setErrorPrintStream(System.err);
		consoleLogger.setOutputPrintStream(System.out);
		consoleLogger.setMessageOutputLevel(Project.MSG_INFO);

		antProject.addBuildListener(consoleLogger);
		try {
			antProject.fireBuildStarted();
			antProject.init();
			ProjectHelper helper = ProjectHelper.getProjectHelper();
			helper.parse(antProject, antFile);
			antProject.executeTarget(antProject.getDefaultTarget());
			antProject.getTargets();
			antProject.fireBuildFinished(null);
		} catch (BuildException e) {
			antProject.fireBuildFinished(e);
		}
	}

	private void doGetUpdateBundles(IProject project) {
		SaturnHttpRequester request = new SaturnHttpRequester();
		InputStream input = null;
		try {

			SaturnServer server = saturnServers.get(comboValue);

			if (server != null) {
				String symbolicName = SaturnBundleUtil
						.getBundleSymbolicName(project);

				String versoin = SaturnBundleUtil.getBundleAttribute(project,
						"Bundle-Version"); //$NON-NLS-1$
				if (versoin == null) {
					versoin = "1.0.0"; //$NON-NLS-1$
				}

				String applicationName = this.getApplicationPath(server
						.getDepolyPath());
				if (applicationName == null) {
					applicationName = "server-main"; //$NON-NLS-1$
				}

				String url = "http://127.0.0.1:" //$NON-NLS-1$
						+ server.getPort()
						+ "/" //$NON-NLS-1$
						+ applicationName
						+ "/edu.ccut.saturn.manager.bundles.impl::/bundleModule/releaseAction/ReleaseBundle.action?" //$NON-NLS-1$
						+ "symbolicName=" + symbolicName + "&versionNum=" //$NON-NLS-1$ //$NON-NLS-2$
						+ versoin;
				System.out.println(url);

				HttpURLConnection connection = request.sendGet(url);

				input = connection.getInputStream();

				String result = this.getResult(input);

				String msg = Messages.getString("DeployDialog.deploy") + project.getName() + Messages.getString("DeployDialog.2"); //$NON-NLS-1$ //$NON-NLS-2$
				if (Messages.getString("DeployDialog.3").equals(result)) { //$NON-NLS-1$
					msg += Messages.getString("DeployDialog.sucess"); //$NON-NLS-1$
				} else {
					msg += Messages.getString("DeployDialog.FailureReason") + result; //$NON-NLS-1$
				}

				this.results.add(msg);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private String getResult(InputStream input) {
		try {
			Document document = SaturnW3CUtil.getDocument(input);

			Node root = document.getDocumentElement();

			String value = SaturnW3CUtil.getChildNodeValue(root, "value"); //$NON-NLS-1$

			return value;
		} catch (XMLException e) {
			e.printStackTrace();
		}

		return "false"; //$NON-NLS-1$
	}

	private String getDepolyPath(String comboValue) {
		if (comboValue.equals("") || comboValue == null) { //$NON-NLS-1$
			return ""; //$NON-NLS-1$
		}

		String path = this.saturnServers.get(comboValue.trim()).getDepolyPath();
		path = path.replace(File.separator, "/"); //$NON-NLS-1$

		if (path.endsWith("/")) { //$NON-NLS-1$
			path = path.substring(0, path.length() - 1);
		}

		return path + "/WEB-INF/bundles/plugins/"; //$NON-NLS-1$
	}

	private String getApplicationPath(String depolyName) {
		if (depolyName.endsWith("/")) { //$NON-NLS-1$
			depolyName = depolyName.substring(0, depolyName.length() - 1);
		}

		int index = depolyName.lastIndexOf("/"); //$NON-NLS-1$
		if (index >= 0 && index < depolyName.length() - 1) {
			return depolyName.substring(index + 1);
		}

		return null;
	}

	protected void restoreWidgetValues() {
		SaturnDialogSettings dialogSettings = SaturnDialogUtil
				.getSaturnDialogSettings(Activator.getDefault());

		String[] urls = dialogSettings.getHistory(STORE_SECTION_NAME,
				STORE_SECTION_NAME);

		if (urls != null && urls.length > 0) {
			String[] items = this.combo.getItems();
			String value = urls[urls.length - 1];
			for (String item : items) {
				if (item.equals(value)) {
					this.combo.setText(item);
					break;
				}
			}
		}
	}

	protected void saveWidgetValues() {
		SaturnDialogSettings dialogSettings = SaturnDialogUtil
				.getSaturnDialogSettings(Activator.getDefault());

		dialogSettings.addHistory(STORE_SECTION_NAME, STORE_SECTION_NAME, combo
				.getText().trim());
	}
}
